package org.jetlinks.pro.assets;

import org.hswebframework.web.authorization.DimensionType;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;

/**
 * 资产绑定管理器,用于管理资产和维度之间的绑定关系.
 * <p>
 * 在进行资产绑定解绑时会触发相应的事件,可以通过监听这些事件进行自定义处理:
 * <pre>{@code
 *
 * @EventListener
 * public void handleBindEvent(AssetsBindEvent event){
 *
 *     event.async(
 *          doHandle(event)
 *     );
 * }
 *
 * }</pre>
 * <p>
 * 还可以通过判断绑定源来处理特殊的逻辑:
 *
 * <pre>{@code
 *
 * @EventListener
 * public void handleBindEvent(AssetsBindEvent event){
 *
 *     event.async(
 *          AssetsUtils
 *          //只有手动绑定才处理
 *              .doWhenSourceIsManualBind(
 *                doHandle(event),
 *                //没设置绑定源也不处理
 *                false
 *         )
 *     );
 * }
 *
 * }</pre>
 *
 * @author zhouhao
 * @see org.jetlinks.pro.assets.event.AssetsBindEvent
 * @see org.jetlinks.pro.assets.event.AssetsUnBindEvent
 * @see org.jetlinks.pro.assets.event.AssetsUnBindAllEvent
 * @see AssetsUtils
 * @since 1.11
 */
public interface AssetBindManager {

    /**
     * 绑定类型:自动绑定,在程序内部进行的绑定时会被标记为自动绑定
     *
     * @see AssetsUtils#doWhenSourceIsAutoBind(Flux, boolean)
     * @see AssetsUtils#doWhenSourceIsAutoBind(Mono, boolean)
     */
    String SOURCE_AUTO = "auto";

    /**
     * 绑定类型:手动绑定,通过接口进行资产分配时
     *
     * @see AssetsUtils#doWhenSourceIsManualBind(Flux, boolean)
     * @see AssetsUtils#doWhenSourceIsManualBind(Mono, boolean)
     */
    String SOURCE_MANUAL = "manual";

    /**
     * 解绑全部资产
     *
     * @param assetType 资产ID
     * @param assetId   资产集合
     * @return void
     * @see org.jetlinks.pro.assets.event.AssetsUnBindAllEvent
     */
    Mono<Integer> unbindAllAssets(@Nonnull String assetType,
                                  @Nonnull Collection<?> assetId);

    /**
     * 绑定资产
     *
     * @param request 绑定请求
     * @return void
     * @see org.jetlinks.pro.assets.event.AssetsBindEvent
     */
    @Nonnull
    Mono<Void> bindAssets(@Nonnull Publisher<AssetBindRequest> request);

    /**
     * 解绑指定资产
     *
     * @param requestFlux 解绑请求
     * @return void
     * @see org.jetlinks.pro.assets.event.AssetsUnBindEvent
     */
    @Nonnull
    Mono<Void> unbindAssets(@Nonnull Publisher<AssetUnbindRequest> requestFlux);

    /**
     * 修改资产权限
     *
     * @param targetType   绑定维度类型
     * @param targetIdList 绑定ID
     * @param assetType    资产类型
     * @param assetIdList  资产ID
     * @param permissions  权限
     * @return void
     */
    Mono<Void> changePermission(@Nonnull String targetType,
                                @Nonnull Collection<String> targetIdList,
                                @Nonnull AssetType assetType,
                                @Nonnull Collection<?> assetIdList,
                                @Nonnull AssetPermission... permissions);

    /**
     * 获取某个维度类型下指定资产类型的指定资产绑定信息
     *
     * @param targetType   维度类型
     * @param targetIdList 维度ID
     * @param assetType    资产类型
     * @param assetIdList  资产Id
     * @return 绑定信息
     */
    @Nonnull
    Flux<AssetBinding> getBindings(@Nonnull String targetType,
                                   @Nonnull Collection<String> targetIdList,
                                   @Nonnull AssetType assetType,
                                   @Nonnull Collection<?> assetIdList);

    /**
     * 根据多个维度类型获取指定资产类型绑定信息
     *
     * @param targetTypes 维度类型
     * @param assetType   资产类型
     * @param assetIdList 资产ID
     * @return 绑定信息
     */
    @Nonnull
    Flux<AssetBinding> getBindings(@Nonnull Collection<String> targetTypes,
                                   @Nonnull AssetType assetType,
                                   @Nonnull Collection<?> assetIdList);

    /**
     * 获取指定维度下某个资产的全部绑定信息
     *
     * @param targetType   维度类型
     * @param targetIdList 维度ID
     * @param assetType    资产类型
     * @return 绑定信息
     */
    @Nonnull
    Flux<AssetBinding> getBindings(@Nonnull String targetType,
                                   @Nonnull Collection<String> targetIdList,
                                   @Nonnull AssetType assetType);

    /**
     * 根据资产类型来获取全部绑定信息
     *
     * @param assetType   资产类型
     * @param assetIdList 资产ID
     * @return 绑定信息
     */
    @Nonnull
    Flux<AssetBinding> getBindings(@Nonnull AssetType assetType,
                                   @Nonnull Collection<?> assetIdList);


    default Flux<AssetBinding> getBindings(DimensionType targetType,
                                           AssetType assetType,
                                           Collection<String> assetIds) {

        return getBindings(Collections.singletonList(targetType.getId()), assetType, assetIds);
    }

}
